Skip to content

Fix for SQLite3::BusyException: database is locked during parallel platform sync#40

Merged
JoshuaMart merged 2 commits into
JoshuaMart:mainfrom
Nishantbhagat57:main
Jun 24, 2026
Merged

Fix for SQLite3::BusyException: database is locked during parallel platform sync#40
JoshuaMart merged 2 commits into
JoshuaMart:mainfrom
Nishantbhagat57:main

Conversation

@Nishantbhagat57

Copy link
Copy Markdown
Contributor

Summary (generated via claude)

Problem
SyncManager#execute_sync runs all platforms concurrently (Concurrent::Promises.future), and each writes to the same SQLite file via DiffEngine. With the default rollback journal, a reader blocks a writer, so under contention a write fails within the 5s timeout and raises database is locked - silently skipping that program for the cycle.

Example: ERROR [hackerone] Failed to process program xyz_bbp: SQLite3::BusyException: database is locked

Fix
Configure SQLite for concurrent access in Database.connect:

  • WAL journal mode so readers no longer block the writer (the actual fix)
  • Busy timeout raised to 10s so writers wait instead of erroring
  • synchronous = NORMAL (recommended WAL pairing)

WAL persists in the DB header, so one call covers all pooled connections; :timeout is applied per-connection by Sequel.

Nishantbhagat57 and others added 2 commits June 24, 2026 01:38
…platform sync

## Summary (generated via claude)
**Problem**
`SyncManager#execute_sync` runs all platforms concurrently (`Concurrent::Promises.future`), and each writes to the same SQLite file via `DiffEngine`. With the default rollback journal, a reader blocks a writer, so under contention a write fails within the 5s timeout and raises `database is locked` - silently skipping that program for the cycle.

Example: `ERROR [hackerone] Failed to process program xyz_bbp: SQLite3::BusyException: database is locked`

**Fix**
Configure SQLite for concurrent access in `Database.connect`:
- WAL journal mode so readers no longer block the writer (the actual fix)
- Busy timeout raised to 10s so writers wait instead of erroring
- `synchronous = NORMAL` (recommended WAL pairing)

WAL persists in the DB header, so one call covers all pooled connections; `:timeout` is applied per-connection by Sequel.
@JoshuaMart

Copy link
Copy Markdown
Owner

Hi,
Thanks for the PR, I just :

  • Moved the pragma setup into Sequel's after_connect hook so synchronous = NORMAL (which is per-connection, not persisted like WAL) applies to every connection in the pool, not just the first.
  • Added specs for the pragmas and gitignored the WAL -wal/-shm side-files.

@JoshuaMart JoshuaMart self-requested a review June 24, 2026 06:05
@JoshuaMart JoshuaMart merged commit 3da9b1e into JoshuaMart:main Jun 24, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants